Skip to content

feat: add set_provider_and_wait() for blocking initialization#567

Draft
leoromanovsky wants to merge 1 commit intoopen-feature:mainfrom
leoromanovsky:feat/set-provider-and-wait
Draft

feat: add set_provider_and_wait() for blocking initialization#567
leoromanovsky wants to merge 1 commit intoopen-feature:mainfrom
leoromanovsky:feat/set-provider-and-wait

Conversation

@leoromanovsky
Copy link

@leoromanovsky leoromanovsky commented Feb 25, 2026

Motivation

The Python SDK is the only major OpenFeature SDK missing set_provider_and_wait(). Java, Go, and Node.js all offer both blocking and non-blocking provider registration. The spec says it SHOULD exist (Requirement 1.1.2.4).

Without this, providers that block in initialize() (waiting for remote config, connecting to a service, etc.) have no way to signal that they're ready before the caller continues. The caller has no SDK-level mechanism to distinguish "provider is initialized and ready" from "set_provider returned but init might still be running."

This was surfaced by Datadog's Python OpenFeature provider (FFL-1843), where initialize() needs to block until Remote Config delivers flag configuration.

Changes

Purely additive -- no existing behavior is changed.

  • set_provider_and_wait(provider, domain?): Same as set_provider() but re-raises initialization exceptions to the caller. If initialize() succeeds, PROVIDER_READY is dispatched and the function returns. If initialize() raises, PROVIDER_ERROR is dispatched AND the exception propagates.
  • set_provider(): Unchanged. Continues to call initialize() synchronously and swallow exceptions (dispatching PROVIDER_ERROR on failure).
  • Added 3 new tests for set_provider_and_wait.

Decisions

  • No behavior change to set_provider(). Changing it to run async would be a breaking change for anyone doing set_provider(p); client.evaluate(...). A note in the docstring suggests making it non-blocking in a future major version to match Java/Go/Node.js SDKs.
  • _and_wait re-raises exceptions -- this is the only behavioral difference from set_provider(). It lets callers use try/except to handle initialization failures, matching setProviderAndWait() in Java (which throws OpenFeatureError).

Spec Reference

Requirement 1.1.2.4: The API SHOULD provide functions to set a provider and wait for the initialize function to return or abnormally terminate.

@gemini-code-assist
Copy link

Summary of Changes

Hello @leoromanovsky, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the OpenFeature Python SDK by implementing both blocking and non-blocking provider initialization mechanisms. The primary goal is to meet a key OpenFeature specification requirement and address issues where providers requiring asynchronous setup could not properly signal their readiness. By introducing set_provider_and_wait() and modifying set_provider() to operate asynchronously, the SDK now offers more robust and flexible control over provider lifecycle management, ensuring better compatibility and developer experience.

Highlights

  • New Blocking Initialization: Introduced set_provider_and_wait() to allow synchronous provider initialization, blocking the calling thread until the provider's initialize() method completes or fails. This aligns with OpenFeature spec requirement 1.1.2.4 and other SDKs.
  • Asynchronous set_provider(): The existing set_provider() function now performs provider initialization in a background daemon thread, making it non-blocking. Errors during initialization are caught and dispatched as PROVIDER_ERROR events without propagating to the caller.
  • Error Handling: Exceptions during set_provider_and_wait() are re-raised to the caller, while exceptions during set_provider()'s background initialization are handled internally and trigger PROVIDER_ERROR events.
  • Test Coverage: Added 5 new tests to cover the behavior of both set_provider_and_wait() (blocking, error propagation, domain support) and the new asynchronous set_provider() (background execution, error handling, eventual readiness).
Changelog
  • openfeature/api.py
    • Exported set_provider_and_wait in the module's __all__.
    • Added the set_provider_and_wait function, which delegates to the provider registry's blocking initialization method.
    • Updated the set_provider function's docstring to clarify its new asynchronous behavior.
  • openfeature/provider/_registry.py
    • Imported the threading module to support background initialization.
    • Refactored set_provider and set_default_provider to use new internal methods (_set_provider_internal, _set_default_provider_internal) with a wait=False flag.
    • Added set_provider_and_wait and set_default_provider_and_wait methods, which call the internal methods with wait=True.
    • Modified the provider initialization logic to conditionally call _initialize_provider (synchronous) or _initialize_provider_async (asynchronous) based on the wait flag.
    • Updated _initialize_provider to re-raise exceptions encountered during initialization.
    • Introduced _initialize_provider_async to run provider initialization in a daemon thread, catching and dispatching exceptions as PROVIDER_ERROR events.
  • tests/test_api.py
    • Imported set_provider_and_wait for testing.
    • Added test_set_provider_and_wait_blocks_until_initialize_completes to verify synchronous initialization.
    • Added test_set_provider_and_wait_raises_on_initialization_failure to confirm exception propagation.
    • Added test_set_provider_and_wait_with_domain to test domain-specific blocking initialization.
    • Added test_set_provider_runs_init_in_background to ensure set_provider does not raise on background initialization failure.
    • Added test_set_provider_async_eventually_becomes_ready to verify asynchronous initialization eventually leads to a READY state.
Activity
  • No specific activity (comments, reviews, progress updates) has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the set_provider_and_wait() function, a valuable addition that aligns the Python SDK with other OpenFeature SDKs and the specification. The implementation is solid, and the new tests provide good coverage. My feedback focuses on a couple of areas for improvement: refactoring some duplicated code in the provider registry for better maintainability, and making the new asynchronous tests more robust by removing time.sleep() in favor of event-based synchronization.

@codecov
Copy link

codecov bot commented Feb 25, 2026

Codecov Report

❌ Patch coverage is 87.93103% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.89%. Comparing base (05382aa) to head (8ddfef0).

Files with missing lines Patch % Lines
openfeature/provider/_registry.py 78.12% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #567      +/-   ##
==========================================
- Coverage   98.18%   97.89%   -0.30%     
==========================================
  Files          41       41              
  Lines        1982     2040      +58     
==========================================
+ Hits         1946     1997      +51     
- Misses         36       43       +7     
Flag Coverage Δ
unittests 97.89% <87.93%> (-0.30%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@leoromanovsky leoromanovsky force-pushed the feat/set-provider-and-wait branch from 8421e98 to 65a0c88 Compare February 25, 2026 14:55
Adds set_provider_and_wait() to the public API, implementing spec
requirement 1.1.2.4: "The API SHOULD provide functions to set a
provider and wait for the initialize function to return or abnormally
terminate."

This is a purely additive change -- set_provider() behavior is
unchanged. The only difference with set_provider_and_wait() is that
initialization errors are re-raised to the caller.

In a future major version, set_provider() should be changed to run
initialize() in a background thread to match the non-blocking
semantics of Java, Go, and Node.js SDKs.

Signed-off-by: Leo Romanovsky <leo.romanovsky@datadoghq.com>
@leoromanovsky leoromanovsky force-pushed the feat/set-provider-and-wait branch from 65a0c88 to 8ddfef0 Compare February 25, 2026 14:59
@gruebel
Copy link
Member

gruebel commented Feb 25, 2026

thanks for the PR, but I don't understand the actual need of this implementation. Currently the provider is synchronically initialized that means when you set a provider it is initialized and you wait till it is done. So, the requirement 1.1.2.4 is currently fulfilled. what doesn't exist is an asynchronous way to do so.

we also don't raise an error on purpose and emit a provider error event.

@leoromanovsky
Copy link
Author

thanks for the PR, but I don't understand the actual need of this implementation. Currently the provider is synchronically initialized that means when you set a provider it is initialized and you wait till it is done. So, the requirement 1.1.2.4 is currently fulfilled. what doesn't exist is an asynchronous way to do so.

we also don't raise an error on purpose and emit a provider error event.

Understood; it's not ready for review yet I'm working on some ideas for the interface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants